import Glibc
class Timer {
    private let CLOCK_REALTIME = 0
    private var start_timespec = timespec()
    private var end_timespec = timespec()
    private var time_spec = timespec()
    func start() {
        clock_gettime(Int32(CLOCK_REALTIME),&start_timespec)
    }
    
    func stop() -> Double {
        clock_gettime(Int32(CLOCK_REALTIME),&end_timespec)
        let start_time = Double(start_timespec.tv_sec * 1_000_000 + start_timespec.tv_nsec / 1_000)
        let end_time = Double(end_timespec.tv_sec * 1_000_000 + end_timespec.tv_nsec / 1_000)
        let time = end_time - start_time
        return time / 1_000
    }
    func getTime() -> Double {
        clock_gettime(Int32(CLOCK_REALTIME),&time_spec)
        return Double(time_spec.tv_sec * 1_000_000 + time_spec.tv_nsec / 1_000)
    }
}

var global = 0

/***************** With parameters *****************/
@inline(never)
func foo(_ a: Int, _ b: Int, _ c: Int) {
    global += 1
}
@inline(never)
func callFoo(_ f: (Int, Int, Int) -> Void, _ a: Int, _ b: Int, _ c: Int) {
    f(a, b, c)
}
/***** Without parameters *****/
@inline(never)
func parameterlessFoo() {
    global += 1
}
@inline(never)
func callParameterlessFoo(_ f: () -> Void) {
    f()
}
/***************************** Default  parameters *****************************/
@inline(never)
func defaultFoo(_ a: Int! = 0, _ b: String! = "b", _ c: Bool! = true) {
    global += 1
}
@inline(never)
func callDefaultFoo(_ f: (Int?, String?, Bool?) -> Void, _ a: Int = 0, _ b: String = "b", _ c: Bool = true) {
    f(nil,nil,nil)
}
/********************* Different  parameters *********************/
@inline(never)
func differentFoo(_ a: Int, _ b: String, _ c: Bool) {
    global += 1
}
@inline(never)
func callDifferentFoo(_ f: (Int, String, Bool) -> Void, _ a: Int, _ b: String, _ c: Bool) {
    f(a, b, c)
}
/************************* Variable  parameters *************************/
@inline(never)
func variableFoo(_ a: Int?, _ b: String?, _ c: Bool?) {
    global += 1
}
@inline(never)
func callVariableFoo(f: (Int?, String?, Bool?) -> Void, _ a: Int?, _ b: String?, _ c: Bool?) {
    f(a, b, c)
}
/***************************** ...Args  parameters *****************************/
@inline(never)
func argsFoo(_ args: Int...) {
    global += 1
}
@inline(never)
func callArgsFoo(_ f: (Int...) -> Void, _ args: Int...) {
    f(args[0], args[1], args[2], args[3], args[4], args[5])
}
// Pointer function call
func runFunctionPtr() -> Int {
    let count = 10000000
    let timer = Timer()
    global = 0
    timer.start()
    for i in 0..<count {
        callFoo(foo, 1, 2, i)
    }
    let time = timer.stop()
    print("Function Call - RunFunctionPtr:\t"+String(time)+"\tms");
    return Int(time)
}
_ = runFunctionPtr()
// Pointer  no parameters function call
func runParameterlessFunctionPtr() -> Int {
    let count = 10000000
    let timer = Timer()
    global = 0
    timer.start()
    for _ in 0..<count {
        callParameterlessFoo(parameterlessFoo)
    }
    let time = timer.stop()
    print("Function Call - RunParameterlessFunctionPtr:\t"+String(time)+"\tms");
    return Int(time)
}
_ = runParameterlessFunctionPtr()
// Pointer function call
func runDeffunctionPtr() -> Int {
    let count = 10000000
    let timer = Timer()
    global = 0
    timer.start()
    for _ in 0..<count {
        callDefaultFoo(defaultFoo)
    }
    let time = timer.stop()
    print("Function Call - RunDefaultfunctionPtr:\t"+String(time)+"\tms");
    return Int(time)
}
_ = runDeffunctionPtr()
// Pointer function call
func runDifFunctionPtr() -> Int {
    let count = 10000000
    let timer = Timer()
    global = 0
    timer.start()
    for _ in 0..<count {
        callDifferentFoo(differentFoo, 1, "1", true)
    }
    let time = timer.stop()
    print("Function Call - RunDifferentFunctionPtr:\t"+String(time)+"\tms");
    return Int(time)
}
_ = runDifFunctionPtr()
// Pointer function call
func runVariableFuncPtr() -> Int {
    let count = 10000000
    let timer = Timer()
    global = 0
    timer.start()
    for _ in 0..<count {
        callVariableFoo(f: variableFoo, 1, "1", true)
    }
    let time = timer.stop()
    print("Function Call - RunVariableFunctionPtr:\t"+String(time)+"\tms");
    return Int(time)
}
_ = runVariableFuncPtr()
// Pointer function call
func runArgsfunctionPtr() -> Int {
    let count = 10000000
    let timer = Timer()
    global = 0
    timer.start()
    for _ in 0..<count {
        callArgsFoo(argsFoo, 1,2,3,4,5,6,7,8,9,10)
    }
    let time = timer.stop()
    print("...Args Parameter Pointer Call:\t\(time)\tms")
    return Int(time)
}
print("Swift Method Call Is End, global value : \(global)")